/**
 * Created by IntelliJ IDEA.
 * User: jiyufei
 * Date: 2018/11/9
 * Time: 14:00
 **/
package com.jiyufei.secure;

import com.jiyufei.bean.SecureAnalysedLog;
import com.jiyufei.bean.SecureLog;
import com.jiyufei.elasticsearch.ElasticSearchOpertator;
import com.jiyufei.util.ElasticSearchInfo;
import com.jiyufei.util.SecureSessionInfo;
import io.searchbox.core.SearchResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SecureSesssion {

    //private RedisCenter redisCenter;
    private ElasticSearchOpertator elasticSearchOpertator;
    private SearchResult searchResult;
    private SecureLog secureLog;
    private SecureRedis secureRedis;
    //private ArrayList<String> redisList;
    private Long resLong,sessionId;
    private List<SearchResult.Hit<SecureLog,Void>> hits;
    private Date queryStartTime;
    private String queryStartTimeStr,queryEndTimeStr;
    private SimpleDateFormat sdf;
    private String newQueryDsl,newUpdateDsl;
    private Pattern patternFirstWord,patternLoginSuccessful,patternUserInvalid,patternFailedPassword;
    private Matcher matcherFirstWord,matcher;
    private SecureAnalysedLog secureAnalysedLog;
    
    
    //可调节参数
    //查询语句中的from间隔条数
    private int step = SecureSessionInfo.QUERY_STEP;
    //查询语句的间隔时间
    private int offsetTime = SecureSessionInfo.QUERY_OFFSET_TIME;
    
    
    
    private String queryDsl = "{\n" +
            "    \"query\":{\n" +
            "        \"bool\":{\n" +
            "            \"must\":{\n" +
            "                \"match_all\":{}\n" +
            "            },\n" +
            "            \"filter\":{\n" +
            "                \"range\":{\n" +
            "                    \"time\":{\n" +
            "                        \"gt\": \"now-2m\",  \n" +
            "                        \"lt\": \"now\",\n" +
            "                        \"format\": \"yyyy-MM-dd HH:mm:ss\",\n" +
            "                        \"time_zone\": \"+0800\"\n" +
            "                    }\n" +
            "                }\n" +
            "            }\n" +
            "        }\n" +
            "    },\n" +
            "    \"sort\":[\n" +
            "        {\"time\":{\"order\":\"asc\"}},\n" +
            "        {\"offset\":\"asc\"}\n" +
            "        ],\n" +
            "    \"from\":0,\n" +
            "    \"size\":30\n" +
            "}";
    
    private String updateDsl = "{\n" +
            "    \"doc\":{\n" +
            "        \"sessionId\":123\n" +
            "    }\n" +
            "}";
    
    private final String regSSHFirstWord = "(\\S+)\\s.+";
    
    //Accepted password for root from 192.168.218.116 port 4928 ssh2
    private final String regSSHLoginSuccessful = "Accepted\\spassword\\sfor\\s(\\S+)\\sfrom\\s((\\d+\\.){3}\\d+)\\sport\\s(\\d+)(.*)";
    //Failed password for root from 42.7.27.164 port 56476 ssh2
    private final String regSSHLoginFailedPassword = "Failed\\spassword\\sfor\\s(\\S+)\\sfrom\\s((\\d+\\.){3}\\d+)\\sport\\s(\\d+)(.*)";
    //Invalid user butter from 81.7.171.64 port 48946
    private final String regSSHLoginUserInvalid = "Invalid\\suser\\s(\\S+)\\sfrom\\s((\\d+\\.){3}\\d+)(\\sport\\s(\\d+)|(.*))";
    
    
    private final static Logger logger = LoggerFactory.getLogger(SecureSesssion.class);
    
    public SecureSesssion(){
        elasticSearchOpertator = new ElasticSearchOpertator();
        //redisList = new ArrayList<>();
        secureRedis = new SecureRedis();
        sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        queryStartTime = new Date();
        patternFirstWord = Pattern.compile(regSSHFirstWord);
        patternLoginSuccessful = Pattern.compile(regSSHLoginSuccessful);
        patternFailedPassword = Pattern.compile(regSSHLoginFailedPassword);
        patternUserInvalid = Pattern.compile(regSSHLoginUserInvalid);
    }
    
    public SecureSesssion(String startTime){
        elasticSearchOpertator = new ElasticSearchOpertator();
        //redisList = new ArrayList<>();
        secureRedis = new SecureRedis();
        sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            queryStartTime = sdf.parse(startTime);
        }catch (Exception e){
            e.printStackTrace();
            logger.error("[SecureSession.SecureSesssion]时间转换失败！" + e.getLocalizedMessage());
        }
        patternFirstWord = Pattern.compile(regSSHFirstWord);
        patternLoginSuccessful = Pattern.compile(regSSHLoginSuccessful);
        patternFailedPassword = Pattern.compile(regSSHLoginFailedPassword);
        patternUserInvalid = Pattern.compile(regSSHLoginUserInvalid);
    }
    
    
    //查询语句的时间管理器，间隔N分钟
    public String timeManager(){
        
        try {
            //校验起始时间，起始时间应小于当前时间-2min
            long diffMin = (new Date().getTime() - queryStartTime.getTime())/(60*1000);
            if(diffMin < offsetTime+2){ //适当放宽时间
                Thread.sleep((Math.abs(diffMin)+2)*60*1000);
            }
            queryStartTimeStr = sdf.format(queryStartTime);
            queryEndTimeStr = sdf.format(queryStartTime.getTime() + (long)offsetTime*60*1000);
            newQueryDsl = queryDsl.replaceAll("gt\": \"now-2m","gt\": \"" + queryStartTimeStr);
            newQueryDsl = newQueryDsl.replaceAll("lt\": \"now","lt\": \"" + queryEndTimeStr);
            queryStartTime = sdf.parse(queryEndTimeStr);
            
            System.out.println("[SecureSession.timeManager]" + queryStartTimeStr + "--" + queryEndTimeStr);
            
        }catch (Exception e){
            e.printStackTrace();
            logger.error("[SecureSession.timeManager]时间转换失败！" + e.getLocalizedMessage());
        }
        return newQueryDsl;
    }
    
    
    public void checkSSHLogin(SecureLog secureLog){
        String firstWord = null;
        secureAnalysedLog = null;
        matcherFirstWord = patternFirstWord.matcher(secureLog.getMessage());
        if(matcherFirstWord.find()){
            firstWord = matcherFirstWord.group(1);
            switch (firstWord){
                case "Accepted":
                    matcher = patternLoginSuccessful.matcher(secureLog.getMessage());
                    if(matcher.find()){
                        secureAnalysedLog = new SecureAnalysedLog();
                        secureAnalysedLog.setId(secureLog.getId());
                        secureAnalysedLog.setLogType("secure");
                        secureAnalysedLog.setType("ssh");
                        secureAnalysedLog.setTime(secureLog.getTime());
                        secureAnalysedLog.setSessionId(secureLog.getSessionId());
                        secureAnalysedLog.setHostIp(secureLog.getClientIp());
                        secureAnalysedLog.setUser(matcher.group(1));
                        secureAnalysedLog.setAttacksIp(matcher.group(2));
                        secureAnalysedLog.setPort(matcher.group(4));
                        secureAnalysedLog.setMsgCode(100000);
                        secureAnalysedLog.setMsg("登录成功");
                        
                    }
                    break;
                case "Invalid":
                    matcher = patternUserInvalid.matcher(secureLog.getMessage());
                    if(matcher.find()){
                        secureAnalysedLog = new SecureAnalysedLog();
                        secureAnalysedLog.setId(secureLog.getId());
                        secureAnalysedLog.setLogType("secure");
                        secureAnalysedLog.setType("ssh");
                        secureAnalysedLog.setTime(secureLog.getTime());
                        secureAnalysedLog.setSessionId(secureLog.getSessionId());
                        secureAnalysedLog.setHostIp(secureLog.getClientIp());
                        secureAnalysedLog.setUser(matcher.group(1));
                        secureAnalysedLog.setAttacksIp(matcher.group(2));
                        secureAnalysedLog.setPort(matcher.group(4));
                        secureAnalysedLog.setMsgCode(100001);
                        secureAnalysedLog.setMsg("尝试使用不存在的用户名登录");
                        System.out.println("Invalid");
                    }
                    break;
                case "Failed":
                    matcher = patternFailedPassword.matcher(secureLog.getMessage());
                    if(matcher.find()){
                        secureAnalysedLog = new SecureAnalysedLog();
                        secureAnalysedLog.setId(secureLog.getId());
                        secureAnalysedLog.setLogType("secure");
                        secureAnalysedLog.setType("ssh");
                        secureAnalysedLog.setTime(secureLog.getTime());
                        secureAnalysedLog.setSessionId(secureLog.getSessionId());
                        secureAnalysedLog.setHostIp(secureLog.getClientIp());
                        secureAnalysedLog.setUser(matcher.group(1));
                        secureAnalysedLog.setAttacksIp(matcher.group(2));
                        secureAnalysedLog.setPort(matcher.group(4));
                        secureAnalysedLog.setMsgCode(100002);
                        secureAnalysedLog.setMsg("登录密码错误");
                    }
                    break;
            }
        }//类型判断
        //写入eleasticsearch
        if(secureAnalysedLog != null){
            elasticSearchOpertator.insertSecureAnalysedLog(secureAnalysedLog);
        }
        
        
    }
    
    
    public void updateSessionId(/*List<SearchResult.Hit<SecureLog,Void>> hits*/){
        int length = hits.size();
        for(int i=0;i<length;i++){
            sessionId = 0L;
            secureLog = hits.get(i).source;
            //System.out.println("[SecureSession.updateSessionId]:" + secureLog.toString());
            if(secureLog.getSessionId() != 0L){
                
                continue;
            }
            secureLog.setId(hits.get(i).id);
            secureLog.setIndex(hits.get(i).index);
            if(secureLog.getProcessId() != null){
                resLong = secureRedis.getSessionId(secureLog.getClientIp(),secureLog.getProcess() + secureLog.getProcessId());
                if(resLong == 0L){
                    //不存在sessionId
                    sessionId = secureRedis.setSessionIdAndTime(secureLog.getClientIp(),secureLog.getProcess() + secureLog.getProcessId(),0);
                }else{
                    //存在sessionId
                    sessionId = resLong;
                }
            }/*else{
                    resLong = secureRedis.getSessionId(secureLog.getClientIp(),secureLog.getProcess());
                    if(resLong == 0L){
                        //不存在sessionId
                        sessionId = secureRedis.setSessionIdAndTime(secureLog.getClientIp(),secureLog.getProcess());
                    }else{
                        //存在sessionId,写入es中
                        sessionId = resLong;
                    }
                }*/
            //更新
            if(sessionId == 0L){
                logger.error("[SecureSesssion.mergeSession]sessionId为0");
            }else{
                secureLog.setSessionId(sessionId);
                newUpdateDsl = updateDsl.replaceAll("123",String.valueOf(sessionId));
                //int result = elasticSearchOpertator.updateElasticSearch(updateDsl,ElasticSearchInfo.SecureIndex,ElasticSearchInfo.secureType)
                int result = elasticSearchOpertator.updateElasticSearch(newUpdateDsl,secureLog.getIndex(),secureLog.getType(),secureLog.getId());
                if(result == 0){
                    System.out.println("[SecureSession.mergeSession]sessionId更新成功");
                }
            }
    
            if(secureLog.getProcess().compareTo("sshd") == 0){
                checkSSHLogin(secureLog);
            }
            
        }
    }
    
    
    public void mergeSession(){
        try {
            
            String myQueryDslFrom = null;
            //List<SearchResult.Hit<SecureLog,Void>> hits = null;
            String myQueryDsl = null;
            
            //无限循环
            while (true){
                myQueryDsl = timeManager();
                searchResult = elasticSearchOpertator.searchElasticSearch(myQueryDsl, ElasticSearchInfo.SecureIndex,ElasticSearchInfo.SecureType);
                hits = searchResult.getHits(SecureLog.class);
                int total = searchResult.getTotal().intValue();
                int offset = step;    //根据查询语句中的size字段设置
                updateSessionId();
    
                System.out.println("[SecureSession.mergeSession]total = " + total);
    
                //返回数量大于30，需要继续查询
                while(total > offset){
                    myQueryDslFrom = myQueryDsl.replaceAll("from\":0","from\":" + offset);
                    offset = offset + step;
                    searchResult = elasticSearchOpertator.searchElasticSearch(myQueryDslFrom, ElasticSearchInfo.SecureIndex,ElasticSearchInfo.SecureType);
                    hits = searchResult.getHits(SecureLog.class);
                    updateSessionId();
                }
            }
            
        }catch (Exception e){
            logger.error("[SecureSesssion.mergeSession]操作出错！Err Msg:" + e.getLocalizedMessage());
        }
    }
    
    
    
    
    
}
